/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package minesweeper.components;

import java.awt.GridLayout;
import javax.swing.JComponent;
import minesweeper.gameaction.GameActionListener;
import minesweeper.gameengine.GameEngine;
import minesweeper.gameover.GameOverListener;
import minesweeper.util.CharArrayBuilder;
import minesweeper.util.Constants;

/**
 *
 * @author cj
 */
public class Board extends JComponent{

    protected boolean[][] reveal;
    protected boolean[][] bombs;
    protected int[][] surroundingBombs;
    protected Sector[][] sectors;

    public Board(int width, int height, int numBombs){
        initMembers(width, height, numBombs);
    }
    
    private void initMembers(int width, int height, int numBombs){
        //Bools are false by default
        this.reveal = new boolean[width][height];
        this.bombs = new boolean[width][height];
        this.sectors = new Sector[width][height];
        this.surroundingBombs = new int[width][height];
        initBombs(numBombs);
        initSectors();
    }
    
    public void addGameActionListenerToAllSectors(GameActionListener listener){
        for(int i = 0; i < this.sectors.length; ++i){
            for(int j = 0; j < this.sectors[i].length; ++j){
                this.sectors[i][j].addGameActionListener(listener);
            }
        }
    }

    public void addGameOverListenersToEngine(GameEngine engine){
        for(int i = 0 ;i < this.sectors.length; ++i){
            for(int j = 0; j < this.sectors[i].length; ++j){
                engine.addGameOverListener(this.sectors[i][j]);
            }
        }
    }
    
    private void initSectors(){
        this.setLayout(new GridLayout(this.sectors[0].length, this.sectors.length));
        
        calculatedSurroundingBombs();

        for(int y = 0; y < this.sectors[0].length; ++y){
            for(int x = 0; x < this.sectors.length; ++x){
                this.sectors[x][y] = new Sector(this.bombs[x][y],
                        Constants.SECTOR_PX_WIDTH, Constants.SECTOR_PX_HEIGHT, this.surroundingBombs[x][y]);
                this.add(this.sectors[x][y]);
            }
        }
        
        initNeighbors();
    }
    
    private void initNeighbors(){
        for(int x = 0; x < this.sectors.length; ++x){
            for(int y = 0; y < this.sectors[x].length; ++y){
                for(int i = x - 1; i <= x + 1; ++i){
                        for(int j = y - 1; j <= y+1; ++j){
                            if(i >= 0 && i < sectors.length
                                    && j >= 0 && j < sectors[i].length
                                    && !(i == x && j == y)){
                                this.sectors[x][y].addNeighborListener(sectors[i][j]);
                            }
                        }
                    }
            }
        }
    }
    
    private void calculatedSurroundingBombs(){
        //Search through bombs
        for(int x = 0; x < bombs.length; ++x){
            for(int y = 0; y < bombs[x].length; ++y){
                //Found a bomb
                if(this.bombs[x][y]){
                    //Now that I've found a bomb, interate around
                    for(int i = x - 1; i <= x + 1; ++i){
                        for(int j = y - 1; j <= y+1; ++j){
                            if(i >= 0 && i < bombs.length
                                    && j >= 0 && j < bombs[i].length
                                    && !(i == x && j == y)){
                                //Mark increase
                                this.surroundingBombs[i][j]++;
                            }
                        }
                    }
                }
            }
        }
    }

    private void initBombs(int numBombs){
        for(int i = 0; i < numBombs; ++i){
            while(!addBomb((int)(Math.random() * (this.bombs.length)),
                     (int)(Math.random() * (this.bombs[0].length)))){}
        }
    }

    private boolean addBomb(int x, int y){
        if(!this.bombs[x][y]){
            this.bombs[x][y] = true;
            return true;
        }
        return false;
    }
    
    public int getSectorWidth(){
        return this.bombs.length;
    }
    
    public int getSectorHeight(){
        return this.bombs[0].length;
    }
    
    public int numAtCoords(int x, int y){
        return this.surroundingBombs[x][y];
    }
    
    public boolean revealedAtCoords(int x, int y){
        return this.sectors[x][y].revealed();
    }
    
    public boolean bombAtCoords(int x, int y){
        return this.bombs[x][y];
    }

    public String toString(){
        String result = "";
        result += "/----------------------------------------------------------\n";
        result += CharArrayBuilder.charArrayToString(CharArrayBuilder.generateCharArray(this));
        return result;
    }

}
